#include "task.h"
#include "wdg.h"
#include "eeprom.h"
#include "stm32l052_lp_mode.h"
#include "app.h"
#include "tftp_server.h"
#include "app_3axis_output.h"
#include "app_ble_irq_handle.h"
#include "stm32_bluenrg_ble.h"
#include "sht3x_dis.h"
#include "voltage.h"

volatile uint8_t dma_in_progress;
extern ble_eeprom_data_t ble_param_data;
extern lis2dh12_param_t sensor_param_data ;
uint32_t task_flag = FALSE;
volatile uint32_t schedule_time = 0;
volatile uint32_t ble_last_connect_time = 0;
uint32_t ble_on_time = 0;
volatile uint32_t random_num;
static uint8_t lis2dh12_init_flag = FALSE;
uint32_t reset_tick = 0;
extern uint16_t combo_data_buf[8];

enum sensor_task{
    RUNNING = 0x00,
    STOP,
};


static volatile uint8_t ble_state = FALSE;
static uint8_t sensor_state = STOP;
static volatile uint32_t ble_adv_offset = 0;
volatile uint8_t adv_state = FALSE, hfc_state = TRUE, connect_state = FALSE, system_state = FALSE;

/*system reset*/
static void system_task_proc(void)
{
    if((system_state == TRUE) && (connect_state == FALSE) && (sensor_state == STOP)){
        
        if((schedule_time - reset_tick) > 2)
            NVIC_SystemReset();
    }
        
}

/*ble*/
static void ble_on(void)
{
    ble_state = TRUE;
    ble_on_time = schedule_time;
 
    if(task_flag == FALSE){
        ble_param_data.adv_period = 300;
    }
    
    // safe zone:  5 -> 35
    
    {
        int segnum;
        int segoff;
        int seed;
        
        seed = random_num % (30 * 5);
        segnum = seed / 30;
        segoff = seed % 30;
     
        ble_adv_offset = segnum * 60 + 5 + segoff;
    }
    
}

static void ble_off(void)
{
    ble_state = FALSE;
    
}

static uint8_t match_ble_start_time(uint32_t schedule_time)
{
    bluenrg_get_config_info(&ble_param_data);
 
    if(task_flag == FALSE){
        ble_param_data.adv_period = 300;
    }
    
    return (schedule_time % ble_param_data.adv_period == ble_adv_offset);
}

static uint8_t match_ble_stop_time(uint32_t schedule_time)
{
    if(task_flag == FALSE){
        ble_param_data.adv_widnow = 20000;
    }
 
    if((schedule_time - ble_on_time) > ((ble_param_data.adv_widnow) / 1000))
        return 0x01;
    else
        return 0x00;
 
}

static void ble_task_proc(void)
{
    /*ble irq*/
    app_ble_irq_handle();
    
    if((!BlueNRG_DataPresent()) && (hfc_state == TRUE))
        app_ip_tx();
 
    if((adv_state == FALSE) && (!BlueNRG_DataPresent()) && (connect_state == FALSE) && (hfc_state == TRUE) && (ble_state == TRUE)){
        hfc_state = FALSE;
        setConnectable();
        adv_state = TRUE;
    }
    
    if((adv_state == TRUE) && (!BlueNRG_DataPresent()) && (connect_state == FALSE) && (hfc_state == TRUE) && (ble_state == FALSE)){
        hfc_state = FALSE;
        bluenrg_stop_adv();
        adv_state = FALSE;
    }
    
    if (ble_state == TRUE) {
     
        if (match_ble_stop_time(schedule_time))
            ble_off();
        
    } else { // OFF
        if (match_ble_start_time(schedule_time))
            ble_on();
    }
}

/*sensor*/

static void sleep_task(void)
{
    if(schedule_time % sensor_param_data.sample_period == 2)
        dma_in_progress = 0;
    
}

static void sht3x_dis_task(void)
{  
    static uint32_t last_time = 0;
 
    if(last_time  != schedule_time){
        if(schedule_time % sensor_param_data.sample_period == 4){
            last_time = schedule_time;

            sht3x_dis_process(&combo_data_buf[6]);
            app_record_cache_store(combo_data_buf);
        }
    }
}

static uint8_t match_sensor_start_time(void)
{
     return (schedule_time % sensor_param_data.sample_period == 0x00);
}

static void start_sensor(void)
{
    sensor_state = RUNNING;
    lis2dh12_get_config_info(&sensor_param_data);
    dma_in_progress = 1;
    lis2dh12_config();
}

static void process_data(void)
{
    lis2dh12_process();
    sensor_state = STOP;
}

static void sensor_task_proc()
{
    if (sensor_state == RUNNING){
        if (app_dma_flag_get() == DMA_END){
         process_data();
        }
    } else { // NOT RUNNING
        if (match_sensor_start_time()) {
            start_sensor();
        }
    }
}

void update_schedule_time(void)
{
    schedule_time = get_time();
}

void call_tasks(void)
{
    if(task_flag == TRUE){
        if(lis2dh12_init_flag == FALSE){
            lis2dh12_begin();
            lis2dh12_init_flag = TRUE;
        }
        sensor_task_proc();
        sleep_task();
        sht3x_dis_task();
    }
    
    ble_task_proc();
    system_task_proc();
 
}

/*task*********************************************************************************************/

static void set_time(uint32_t time)
{
    rtc_set_new_time(time);
    update_schedule_time();
}

/*tftp time set***********************************************************************************/
bool _time_cmd_open(char* name, uint8_t mode)
{
    if (mode != TFTP_WRQ) return false;
    
    if (0 == strcmp(name, "time.set")) {
        return true;
    } else {
        return false;
    }
}

uint16_t (_time_cmd_read)(uint8_t blk, uint8_t* buffer)
{
    return 0;
}

void (_time_cmd_write)(uint8_t blk, uint8_t* buffer, uint16_t len)
{
    set_time(*(uint32_t*)buffer);
}

void (_time_cmd_close)(void)
{

}

const tftp_server_plugin_t tftp_server_plugin_time_cmd = {
    _time_cmd_open,
    _time_cmd_read,
    _time_cmd_write,
    _time_cmd_close,
};

/*tftp system reset***********************************************************************************/
bool _systerm_reset_cmd_open(char* name, uint8_t mode)
{   
    if (mode != TFTP_WRQ) return false;
 
    if (0 == strcmp(name, "system.reset")) {
        return true;
    } else {
        return false;
    }
}

uint16_t (_systerm_reset_cmd_read)(uint8_t blk, uint8_t* buffer)
{
   
    return 0;
}

void (_systerm_reset_cmd_write)(uint8_t blk, uint8_t* buffer, uint16_t len)
{
   
   

}

void (_systerm_reset_cmd_close)(void)
{
     system_state = TRUE;
     reset_tick = schedule_time;
}

const tftp_server_plugin_t tftp_server_plugin_systerm_reset_cmd = {
    _systerm_reset_cmd_open,
    _systerm_reset_cmd_read,
    _systerm_reset_cmd_write,
    _systerm_reset_cmd_close,
};
